package testset;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import lv.rtu.ditf.dc.classification.ClassificationUtils;
import lv.rtu.ditf.dc.fs.Document;
import lv.rtu.ditf.dc.fs.DocumentCategory;
import lv.rtu.ditf.dc.fs.FileStorage;
import lv.rtu.ditf.dc.hashmap.routines.HashMapRoutines;
import lv.rtu.ditf.dc.keyvalue.CategorizationClassPointComparator;
import lv.rtu.ditf.dc.keyvalue.CategorizationClassPointKeyValue;

/**
 * 
 * @author Pāvels Koliškins, Edgars Matisāns
 *
 */
public class CategorizationThread extends Thread {

    private HashMap<String, Integer> documentToClassifyVector;
    private final int kNNParameter;
    private final double epsilon;
    private final String correctCategory;
    private long executionStartTime;
    private long executionEndTime;
    private int categorizationPercent;

    public long getExecutionEndTime() {
        return executionEndTime;
    }

    public void setExecutionEndTime(long executionEndTime) {
        this.executionEndTime = executionEndTime;
    }

    public int getCategorizationPercent() {
        return categorizationPercent;
    }

    public void setCategorizationPercent(int categorizationPercent) {
        this.categorizationPercent = categorizationPercent;
    }

    public long getExecutionStartTime() {
        return executionStartTime;
    }

    public void setExecutionStartTime(long executionStartTime) {
        this.executionStartTime = executionStartTime;
    }

    public HashMap<String, Integer> getDocumentToClassifyVector() {
        return documentToClassifyVector;
    }

    public void setDocumentToClassifyVector(HashMap<String, Integer> testDocumentVector) {
        this.documentToClassifyVector = testDocumentVector;
    }
    
    public CategorizationThread(HashMap<String, Integer> testDocumentVector, int kNNParameter,
            double epsilon, String correctCategory) {
        this.documentToClassifyVector = testDocumentVector;
        this.kNNParameter = kNNParameter;
        this.epsilon = epsilon;
        this.executionStartTime = 0;
        this.correctCategory = correctCategory;
        this.categorizationPercent = 0;
        this.executionEndTime = 0;
    }

    @Override
    public void run() {
        this.executionStartTime = System.currentTimeMillis();

        ArrayList<CategorizationClassPointKeyValue> categorizationResults = new ArrayList<CategorizationClassPointKeyValue>();

        try {
            FileStorage fileStorage = FileStorage.get();
            List<DocumentCategory> documentCategories = fileStorage.getDocumentCategories();
            int totalDocumentCount = fileStorage.getTotalDocumentCount();
            HashMap<String, Integer> docCountByTerm = fileStorage.getDocumentCountByTerm();
            
            for (DocumentCategory documentCategory : documentCategories) {
            	
                List<Document> categoriesDocuments = documentCategory.getDocuments();
                for (Document categoryDocument : categoriesDocuments) {

                    double distance = ClassificationUtils.getCosineSimilarity(
                            getDocumentToClassifyVector(), 
                            categoryDocument.getTermWeights(totalDocumentCount, docCountByTerm));
                    
                    if (Double.isNaN(distance)) distance = 0.0;
                    
                    categorizationResults.add(
                            new CategorizationClassPointKeyValue(documentCategory.getName(), distance));
                }
            }

            
            Collections.sort(categorizationResults, new CategorizationClassPointComparator());
            
            //leave only kNN values in list
            //kNN is guaranteed to be between 1 and MAX_DOCUMENTS
            List<CategorizationClassPointKeyValue> categorizationResultSubList = categorizationResults.subList(0, kNNParameter);
            
            //if first element is list is less than EPSILON
            //document cannot be categorized
            if (categorizationResultSubList.size() > 0) {
                if (categorizationResultSubList.get(0).getDistancePoint() < this.epsilon) {
                    categorizationResultSubList.clear();
                }
            }
            System.out.println(categorizationResultSubList);

            //get percent ration
            double pointsCollected = 0d;
            HashMap<String, Double> statisticHashMap = new HashMap<String, Double>();
            for (CategorizationClassPointKeyValue categorizationClassPointKeyValue: categorizationResultSubList) {

                if (statisticHashMap.get(categorizationClassPointKeyValue.getCategorizationClass()) == null) {
                    statisticHashMap.put(categorizationClassPointKeyValue.getCategorizationClass(),
                            categorizationClassPointKeyValue.getDistancePoint());
                } else {
                    statisticHashMap.put(categorizationClassPointKeyValue.getCategorizationClass(),
                            statisticHashMap.get(categorizationClassPointKeyValue.getCategorizationClass()) +
                            categorizationClassPointKeyValue.getDistancePoint());
                }

                pointsCollected += categorizationClassPointKeyValue.getDistancePoint();
            }
            for (String categoryName : statisticHashMap.keySet()) {
                statisticHashMap.put(categoryName,
                        statisticHashMap.get(categoryName) / pointsCollected);
            }
            //sorting hash map with percents
            List<String> sortedKeys = HashMapRoutines.sortByValueDesc(statisticHashMap);
            
            System.out.println(sortedKeys);

            //due to precision loss, make sure in sum there are 100%
            int percents = 0;
            for (String categoryName : sortedKeys) {
                percents += (int)(statisticHashMap.get(categoryName) * 100);
            }
            int percentsToAdd = 100 - percents;
            
            boolean wasFirstRecordRead = false;
            for (String categoryName : sortedKeys) {
                int tmpPercent = 0;
                if (!wasFirstRecordRead) {
                    wasFirstRecordRead = true;
                    tmpPercent = ((int)(statisticHashMap.get(categoryName) * 100) + percentsToAdd);
                } else {
                    tmpPercent = (int)(statisticHashMap.get(categoryName) * 100);
                }
                
                if (categoryName.trim().equalsIgnoreCase(correctCategory.trim())) {
                    categorizationPercent = tmpPercent;
                }
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        executionEndTime = System.currentTimeMillis();

        System.out.println(executionStartTime + " - " + executionEndTime);
        System.out.println(categorizationPercent);
        System.out.println("----------------------------");
    }
}
